﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX.DirectSound;
using DS = Microsoft.DirectX.DirectSound;

namespace PlayBox
{
    /// <summary>
    /// this class provides the functionality of a music player to play our encrypted sound files
    /// </summary>
    public partial class MusicPlayer : Form
    {
        private DS.Device soundDevice;
        private SecondaryBuffer soundBuffer;
        private BufferDescription desc;
        private Control control;
        private DataClasses.Music song;
        private int bufferLen;

        /// <summary>
        /// constructor
        /// </summary>
        private MusicPlayer()
        {
            soundDevice = new DS.Device();
            desc = new BufferDescription();
            desc.ControlEffects = false;

            control = new Control();
            soundDevice.SetCooperativeLevel(control, CooperativeLevel.Normal);
        }

        private static MusicPlayer instance = null;

        /// <summary>
        /// gets the instances that should be used
        /// </summary>
        /// <returns></returns>
        private static MusicPlayer getInstance()
        {
            if (instance == null)
            {
                instance = new MusicPlayer();
                instance.InitializeComponent();
            }
            return instance;
        }
        /// <summary>
        /// show the player
        /// </summary>
        public static void Show()
        {
            Form form = getInstance();
            form.Show();
            getInstance().timerPlayPosition.Enabled = true;
        }
        /// <summary>
        /// hide the player
        /// </summary>
        public static void Hide()
        {
            getInstance().timerPlayPosition.Enabled = false;
            stopPlayback();
            Form form = getInstance();
            form.Hide();

        }
        /// <summary>
        /// plays the given song
        /// </summary>
        /// <param name="_song">the song to play</param>
        public static void playSong(DataClasses.Music _song)
        {
            getInstance().song = _song;
            Show();
            SecondaryBuffer buffer = getInstance().soundBuffer;
            _song.SongStream.Seek(0, System.IO.SeekOrigin.Begin);
            getInstance().bufferLen = (int)_song.SongStream.Length;
            buffer = new SecondaryBuffer(_song.SongStream,getInstance().desc, getInstance().soundDevice);
            buffer.Play(0, BufferPlayFlags.Default);
            getInstance().soundBuffer = buffer;
            getInstance().txtSongInfo.Text = _song.Artist + " - " + _song.Title;
            getInstance().scrollSeeker.Value = 0;
            getInstance().scrollSeeker.Maximum = getInstance().bufferLen;
        }
        /// <summary>
        /// sets the play position to the given pos
        /// </summary>
        /// <param name="pos">the new play position</param>
        public static void setPlayPosition(int pos)
        {
            SecondaryBuffer buffer = getInstance().soundBuffer;
            buffer.SetCurrentPosition(pos);
        }
        /// <summary>
        /// used to relatively set a new play position, can be used for forward/backward
        /// scrolling (negativ offset will go back in time)
        /// </summary>
        /// <param name="offset"></param>
        public static void setRelativePlayPosition(int offset)
        {
            SecondaryBuffer buffer = getInstance().soundBuffer;
            int pos = buffer.PlayPosition + offset;
            if (pos > 0 && pos < getInstance().bufferLen)
            {
                buffer.SetCurrentPosition(buffer.PlayPosition + offset);
            }
        }
        /// <summary>
        /// gets the current play position
        /// </summary>
        /// <returns>the current play position</returns>
        public static int getPlayPosition()
        {
            return getInstance().soundBuffer.PlayPosition;
        }
        /// <summary>
        /// stops the playback
        /// </summary>
        /// <param name="reset"></param>
        public static void stopPlayback(bool reset = false)
        {
            getInstance().soundBuffer.Stop();
            if (reset)
            {
                setPlayPosition(0);
            }
        }
        /// <summary>
        /// retrieves the maximum play position (length of song)
        /// </summary>
        /// <returns></returns>
        public static int getMaximumPosition()
        {
            return getInstance().bufferLen;
        }
        /// <summary>
        /// handles clicks on the stop button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btStop_Click(object sender, EventArgs e)
        {
            stopPlayback(true);
        }
        /// <summary>
        /// handles clicks on the play button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btPlay_Click(object sender, EventArgs e)
        {
            SecondaryBuffer buffer = getInstance().soundBuffer;
            if (buffer.Status.Playing)
            {
                stopPlayback();
            }
            else
            {
                buffer.Play(0, BufferPlayFlags.Default);
            }
        }
        /// <summary>
        /// prevent the form closing event, hide the form instead
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MusicPlayer_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            Hide();
        }
        /// <summary>
        /// handles clicks on the forward button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btForward_Click(object sender, EventArgs e)
        {
            setRelativePlayPosition(500000);
        }
        /// <summary>
        /// handles clicks on the backward button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btBackward_Click(object sender, EventArgs e)
        {
            setRelativePlayPosition(-500000);
        }

        /// <summary>
        /// handles the tick event of the timer
        /// this is used for updating the scrollbar to the current play position
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerPlayPosition_Tick(object sender, EventArgs e)
        {
            scrollSeeker.Value = getPlayPosition();
        }
        /// <summary>
        /// handles scrolling events of the scrollbar
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void scrollSeeker_Scroll(object sender, ScrollEventArgs e)
        {
            setPlayPosition(scrollSeeker.Value);
        }
    }
}
